<html>
<head>
<style>
  .ace_editor {
    border: 0;
    width: auto;
    height: 100%;
    margin: 0;
    top:0;
    right:0;
    bottom:0;
    left:0;
    z-index: 10000;
    touch-action: none;
  }

  body {
    padding: 0px;
    margin: 0px;
    overflow: hidden;
    -ms-overflow-style: scrollbar;
  }
</style>
</head>
<body>
<textarea id="source">package com.sencha.gxt.explorer.client.grid;

import com.google.gwt.dom.client.Style;
import com.sencha.gxt.core.client.GXT;
import com.sencha.gxt.core.client.dom.XElement;
import com.sencha.gxt.widget.core.client.grid.ColumnConfig;
import com.sencha.gxt.widget.core.client.grid.ColumnHeader;
import com.sencha.gxt.widget.core.client.grid.ColumnModel;
import com.sencha.gxt.widget.core.client.grid.Grid;
import com.sencha.gxt.widget.core.client.grid.GridView;

/**
 * A {@link Grid} {@link ColumnHeader} that supports word wrap, enabling long column headings to be displayed in
 * multiple rows. Provides options for letting the height of the header default to the height of the tallest heading, or
 * to be manually set to a specific pixel value.
 * <p></p>
 * In order for a heading to word wrap, the heading must be set to HTML that enables word wrap, e.g.
 * &lt;span style='white-space: normal;'&gt;A very long heading&lt;/span&gt;.
 */
public class WordWrapColumnHeader<M> extends ColumnHeader<M> {

  protected class WordWrapHead extends ColumnHeader<M>.Head {
    @SuppressWarnings({"rawtypes"})
    public WordWrapHead(ColumnConfig column) {
      super(column);
      getElement().getStyle().setFloat(Style.Float.NONE);
    }
  }

  private int fixedHeight = -1;

  /**
   * Constructs a new word wrap column header for the specified grid and column model. To configure the grid to use the
   * new word wrap column header, invoke {@link GridView#setColumnHeader(ColumnHeader)}, e.g.
   * grid.getView().setColumnHeader(new WordWrapColumnHeader&lt;T&gt;(g, cm).
   * 
   * @param container - the grid that contains this word wrap column header
   * @param cm - the column model that provides the configuration for this column header
   */
  public WordWrapColumnHeader(Grid<M> container, ColumnModel<M> cm) {
    super(container, cm);
  }

  /**
   * Sets the height of the word wrap column header to a specific value. Generally this is not required as the column
   * header sizes itself to the height of the tallest heading. However, there are some use cases where the column header
   * height must be set (e.g. linked grids displayed side-by-side, where the column header height of one grid must match
   * that of the other).
   * 
   * @param newHeight the height of the column header, or -1 to resize the header to the height of it's tallest heading
   *          (i.e. it's "natural" height)
   */
  @Override
  public void setHeight(int newHeight) {
    if (GXT.isIE()) {
      getElement().getOffsetParent().setScrollTop(0);
    }

    // Do not forward to base class... the parent element must remain unsized
    fixedHeight = newHeight;
    if (newHeight == -1) {
      setNaturalHeight();
    } else {
      setFixedHeight(newHeight);
    }
    super.checkHeaderSizeChange();
  }

  @Override
  protected void checkHeaderSizeChange() {
    onHeaderSizeChange();
    super.checkHeaderSizeChange();
  }

  @Override
  @SuppressWarnings("rawtypes")
  protected Head createNewHead(ColumnConfig config) {
    return new WordWrapHead(config);
  }

  private int getContentHeight() {
    int height = 0;
    int columnCount = cm.getColumnCount();
    for (int columnIndex = 0; columnIndex < columnCount; columnIndex++) {
      if (!cm.isHidden(columnIndex)) {
        Head head = getHead(columnIndex);
        XElement inner = head.getElement();
        height = Math.max(height, inner.getOffsetHeight());
      }
    }
    
    // adjust to allow space for sort icon
    height += 5;
    return height;
  }

  private void onHeaderSizeChange() {
    if (fixedHeight == -1) {
      setNaturalHeight();
    } else {
      setFixedHeight(fixedHeight);
    }
  }

  private void setFixedHeight(int newHeight) {
    int offsetHeight = getOffsetHeight();
    int contentHeight = getContentHeight();
    int deltaHeight = offsetHeight - contentHeight;
    newHeight -= deltaHeight;
    overrideHeaderHeight = newHeight;
    refresh();
  }

  private void setNaturalHeight() {
    overrideHeaderHeight = -1;
    refresh();
  }

}
</textarea>

<script src="../../samples/ace/ace.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
  var type = "{type}";
  if (type == ("{" + "type}")) {
    // something went wrong, use java as default
    type = "java";
  }
  var editor = ace.edit("source");
  var mode = "ace/mode/" + type;
  var theme = "ace/theme/chrome";
  var readOnly = true;
  editor.getSession().setMode(mode);
  editor.getSession().setUseWorker(false);
  editor.setTheme(theme);
  editor.setShowPrintMargin(false);
  editor.renderer.setShowGutter(true);
  editor.setHighlightActiveLine(false);
  editor.setDisplayIndentGuides(true);
  editor.setReadOnly(readOnly);
  editor.renderer.setPadding(10);
  editor.renderer.setScrollMargin(10, 10, 0, 0);
  editor.getSession().setOptions({
    tabSize: 8,
    useSoftTabs: true,
    useWrapMode: false,
  });
</script>
</body>
</html>